package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

// 启动web服务器,使用http服务，使用handlefunc
func ServeHttp(p http.ResponseWriter, r *http.Request) {
	fmt.Fprint(p, "通过handlefunc启动http服务") //输出到浏览器
}

type DefineServer struct{}

// 启动web服务器,使用http服务，使用handle，给DefineServer添加一个函数
func (dsm *DefineServer) ServeHTTP(p http.ResponseWriter, r *http.Request) { //ServeHTTP是内置的接口
	fmt.Fprint(p, "通过自定义类型启动http服务")
	//url:[scheme:][//host][/]path[?query][#fragment]
	fmt.Fprint(p, r.URL.RawQuery) //？query部分
	fmt.Fprint(p, r.URL.Host)
	fmt.Fprint(p, r.URL.Path)
	//拿？后面
	raw := r.URL.RawQuery
	va, _ := url.ParseQuery(raw)                      //多个相同parseQuary只返回第一个
	fmt.Fprint(p, "获取url中key为name的值", va.Get("name")) //输出到浏览器
}

// 发送请求结构体http body, 在终端里可以使用curl -id去本地测试不用打开浏览器直接看响应包，方法：
// curl -id "action=search&book=全站编程" localhost:8080/body
func getHttpBody(p http.ResponseWriter, r *http.Request) {
	len := r.ContentLength //http的Request类型的body长度名,byte形式储存
	body := make([]byte, len)
	r.Body.Read(body)
	fmt.Fprintln(p, string(body))
}

// 获取多表单的form-data
func MultiPaltform(p http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(1024)                          //内置要求必须调用ParseForm这个方法，最大内存数要指定，超出的部分会保存在缓存里
	fileHeader := r.MultipartForm.File["fileupload"][0] //map类型 key是input的name
	f, err := fileHeader.Open()
	if err != nil {
		fmt.Fprintf(p, "出现错误")
	} else {
		data, err := ioutil.ReadAll(f) //ioutil读取文件
		if err == nil {
			fmt.Fprintln(p, "%s\n", data) //如果是浏览器无法识别的文件比如zip文件，会自动下载
		}
	}
	fmt.Fprint(p, r.PostForm)
	fmt.Fprint(p, r.Form)
}

// formvalue和postformvalue方法(只适用于post表单），获取表单中的数据，不需要手动调用ParseForm就可以直接读表单
func FormPostValue(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "enctype=\"application/x-www-form-urlencoded\"", r.FormValue("username"), r.FormValue("website"))
	fmt.Fprint(w, "enctype=\"multipart/form-data\"", r.PostFormValue("password"))
	//获取文件file,第一个是file表单中的name
	f, _, err := r.FormFile("fileupload") //多种类型的表单要用enctype=mutipart
	if err == nil {                       //文件上传正常
		data, erro := ioutil.ReadAll(f)
		if erro == nil { //文件读取正常
			fmt.Fprint(w, "%s\n", string(data)) //无法解析的文件就会下载（浏览器zip、word、png等）
		}
	} else {
		fmt.Fprint(w, err.Error())
	}
}

func main() {
	http.HandleFunc("/", ServeHttp) //路由地址
	defined := DefineServer{}
	http.Handle("/getUserInfo", &defined) //增加路由地址,handle需要指针
	http.HandleFunc("/body", getHttpBody)
	http.HandleFunc("/muti", MultiPaltform)     //多表单
	http.HandleFunc("/formPost", FormPostValue) //formvalue读表单
	http.ListenAndServe(":8080", nil)           //浏览器打开8080端口localhost:8080
}
